//
// Created by vivi on 07/02/2018.
//

#include "core/hairgeo/hairgeo.h"
#include "core/collider/sdfcollider.h"
#include "core/engine/andrewsellehe.h"
#include "core/constant/constants.h"
#include "core/collision/spherecollisionobj.h"
#include "core/collision/uniformgridcollisionobj.h"
#include "core/collision/boxcollisionobj.h"
#include "core/collision/sdfcollisionobj.h"
#include "../core/solver/hair.h"
#include <Eigen/Eigen>
#include <limits>
#include <memory>

using namespace Eigen;
using namespace HairEngine;
using namespace std;

istream &operator>>(istream & is, Eigen::Affine3f &affine3f) {
	Matrix4f m;
	float f;
	for (size_t i = 0; i < 4; ++i)
		for (size_t j = 0; j < 4; ++j) {
			is >> f;
			m(i, j) = f;
		}
	affine3f = Eigen::Affine3f(m);
	return is;
}

int olMain() {
	StrandBasedHairGeometry geo("/Users/vivi/Developer/project/Hair Simulation/Houdini/Scenes/Scene-2/3/Hair-Small-2.hair");

	AndrewSelleHairEngine::Configuration conf(
			1000000.0f, //Spring stiffness
			20000.0f, //Bending stiffness
			20000.0f, //Torsion stiffness
			200.0f, //Altitude spring siffness
			1000.0f, //Contact stiffness
			4000.0f, //Damping
			15.0f, //Wind damping
			25.0f, //Strand mass
			AndrewSelleHairEngine::StrandMassDistributionNormal({1.0f, 1.0f}),
			{0.0f, -9.81f, 0.0f}, //Gravity
			0.005f, //Max simulation time
			AndrewSelleHairEngine::Configuration::IntegrationMethod::Default, //Default Integrator
			false, //Enable strain limiting
			0.1f, //Strain dynamic tolerance
			true, //Enable body collision
			0.005f, //Body collision relative isocontour value
			false, //Enable hair contacts
			5e-4f, //Hair contacts creating distance
			2.5e-3f, //Hair contacts breaking distance
			10, //Hair contacts max contact per segment
			5e-4f, //Hair contacts grid size
			400, //Hair contacts max grid resolution
			true,
			10,
			5e-4f
	);

	fstream transformFile("/Users/vivi/Developer/project/Hair Simulation/Houdini/Scenes/Scene-2/3/Transform.txt", ios::in);
	Affine3f transform;

	transformFile >> transform;

	shared_ptr<CollisionObject> collisionObjectPtr = make_shared<SignedDistanceFieldCollisionObject>("/Users/vivi/Developer/project/Hair Simulation/Houdini/Scenes/Scene-2/3/Collision.sdf2", transform);
	HairEngineSimulationData simulationData(transform);

	AndrewSelleHairEngine hairEngine(
			geo,
			conf,
			collisionObjectPtr
	);

	VPlyOptions vplyOptions = VPlyOptions(Particles | InternalSprings | HairContactsSpring | HairCollisionsSpring);
	float simulationTime = 0.005f;

	//hairEngine.reGeometry(20, 0.01, 0.0f, false);

	hairEngine.writeVPlyToFile("/Users/vivi/Desktop/AndrewSelleHairEngine/0.vply", vplyOptions);
	for (size_t i = 1; i < 200 ; ++i) {
		cout << "Current frame: " << i << endl;

		cout << "Current transform is: " << EigenUtility::toString(transform.matrix()) << endl;

		simulationData.update(transform, simulationTime);

		ostringstream os;
		os << "/Users/vivi/Desktop/AndrewSelleHairEngine/" << i;

		hairEngine.updateCollisionTransform(transform, simulationData.t, false);
		hairEngine.simulate(simulationData);
		hairEngine.writeVPlyToFile(os.str() + ".vply", vplyOptions);
		hairEngine.writeToFile(os.str() + ".hair");

//		if (!(transformFile >> transform))
//			break;
	}

	return 0;
}

int newMain() { 
	Hair hair("/Users/vivi/Developer/project/Hair Simulation/Houdini/Scenes/Scene-2/3/Hair-Small-2.hair");

	hair.writeToFile("/Users/vivi/Desktop/testHair.hair");

	return 0;
}

int main() {
	return newMain();
}